#include "DVPP_VPC.h"


DVPP_VPC::DVPP_VPC(/* args */)
{
}

DVPP_VPC::~DVPP_VPC()
{
}



int DVPP_VPC::dvppInit()
{
    // ACL init
    const char *aclConfigPath = nullptr;
    aclError ret = aclInit(aclConfigPath);
    if (ret) {
        std::cout<<"acl get run mode failed"<<std::endl;
        return 1;
    }
    
    // open device
    ret = aclrtSetDevice(0);
    if (ret) {
        std::cout<<"Acl open device failed"<<std::endl;
        return 1;
    }

    // create context
    ret = aclrtCreateContext(&g_context_, 0);
    if (ret) {
        std::cout<<"acl create context failed"<<std::endl;
        return 1;
    }

    // create stream
    ret = aclrtCreateStream(&g_stream_);
    if (ret) {
        std::cout<<"acl create stream failed"<<std::endl;
        return 1;
    }

    // DVPP 创建图片数据处理通道时的通道描述信息
    g_dvppChannelDesc_ = acldvppCreateChannelDesc();
    if (g_dvppChannelDesc_ == nullptr) {
        std::cout<<"acldvppCreateChannelDesc failed"<<std::endl;
        return 1;
    }

    // 创建图片数据处理的通道
    aclError aclRet = acldvppCreateChannel(g_dvppChannelDesc_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"acldvppCreateChannel failed"<<std::endl;
        return 1;
    }
    std::cout<<"dvpp init resource ok"<<std::endl;

    return 0;
}




int DVPP_VPC::dvpp_resize(unsigned char * srcImage, uint32_t len, int input_w, int input_h, int output_w, int output_h)
{

    void* buffer = nullptr;
    aclError aclRet = acldvppMalloc(&buffer, len);
    aclRet = aclrtMemcpy(buffer, len, srcImage, len, ACL_MEMCPY_HOST_TO_DEVICE);

    // 1. 创建图片缩放配置数据、指定缩放算法
    g_resizeConfig_ = acldvppCreateResizeConfig();   
    if (g_resizeConfig_ == nullptr) {
        std::cout<<"Dvpp resize init failed for create config failed"<<std::endl;
        return 1;
    }                  
    aclError ret = acldvppSetResizeConfigInterpolation(g_resizeConfig_, 0);
    
    //2. 创建图片数据处理通道时的通道描述信息
    g_vpcInputDesc_ = acldvppCreatePicDesc();
    if (g_vpcInputDesc_ == nullptr) {
        std::cout<<"acldvppCreatePicDesc g_vpcInputDesc_ failed"<<std::endl;
        return 1;
    }

    //3. 创建缩放输入图片的描述信息，并设置各属性值
    g_inputBufferSize_ = YUV420SP_SIZE(input_w, input_h);

    acldvppSetPicDescData(g_vpcInputDesc_, buffer);
    acldvppSetPicDescFormat(g_vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(g_vpcInputDesc_, input_w);
    acldvppSetPicDescHeight(g_vpcInputDesc_, input_h);
    acldvppSetPicDescWidthStride(g_vpcInputDesc_, input_w);
    acldvppSetPicDescHeightStride(g_vpcInputDesc_, input_h);
    acldvppSetPicDescSize(g_vpcInputDesc_, g_inputBufferSize_);

    //4. 创建缩放输出图片的描述信息，并设置各属性值
    g_OutputBufferSize_ = YUV420SP_SIZE(output_w, output_h);
    aclRet = acldvppMalloc(&g_vpcOutBufferDev_, g_OutputBufferSize_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"acldvppMalloc g_vpcOutBufferDev_ failed"<<std::endl;
        return 1;
    }
    g_vpcOutputDesc_ = acldvppCreatePicDesc();
    if (g_vpcOutputDesc_ == nullptr) {
        std::cout<<"acldvppCreatePicDesc g_vpcOutputDesc_ failed"<<std::endl;
        return 1;
    }

    acldvppSetPicDescData(g_vpcOutputDesc_, g_vpcOutBufferDev_);
    acldvppSetPicDescFormat(g_vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(g_vpcOutputDesc_, output_w);
    acldvppSetPicDescHeight(g_vpcOutputDesc_, output_h);
    acldvppSetPicDescWidthStride(g_vpcOutputDesc_, output_w);
    acldvppSetPicDescHeightStride(g_vpcOutputDesc_, output_h);
    acldvppSetPicDescSize(g_vpcOutputDesc_, g_OutputBufferSize_);

    // resize pic
    aclRet = acldvppVpcResizeAsync(g_dvppChannelDesc_, g_vpcInputDesc_, g_vpcOutputDesc_, g_resizeConfig_, g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"acldvppVpcResizeAsync failed, ret = "<<aclRet<<std::endl;
     
    }

    // 执行异步缩放，再调用aclrtSynchronizeStream接口阻塞程序运行，直到指定Stream中的所有任务都完成
    aclRet = aclrtSynchronizeStream(g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"aclrtSynchronizeStream failed, ret = "<<aclRet<<std::endl;
    
    }

    // g_imageDataBuf_ = g_vpcOutBufferDev_;

    //  保存查看，device2host
    void* buffer1 = nullptr;
    aclRet  = aclrtMallocHost(&buffer1, 614400);
    if (aclRet != ACL_SUCCESS) {
	std::cout << "aclrtMallocHost failed, result code is " << aclRet << std::endl;
    }
    
    aclRet = aclrtMemcpy(buffer1, 614400, g_vpcOutBufferDev_, 614400, ACL_MEMCPY_DEVICE_TO_HOST);
    FILE *fp;
    fp = fopen("./resize_640_640.yuv", "w");
    fwrite((unsigned char *)buffer1, sizeof(unsigned char), 614400, fp);  // 1966080 614400
    fclose(fp);

    dvpp_resizeUninit();
    return 0;
}

int DVPP_VPC::dvpp_jpege(unsigned char * srcImage, uint32_t len, int input_w, int input_h)
{   
    void* buffer = nullptr;
    aclError aclRet = acldvppMalloc(&buffer, len);
    aclRet = aclrtMemcpy(buffer, len, srcImage, len, ACL_MEMCPY_HOST_TO_DEVICE);

    encodeInputDesc_ = acldvppCreatePicDesc();
    uint32_t buffer_size = YUV420SP_SIZE(input_w, input_h);

    acldvppSetPicDescData(encodeInputDesc_, buffer);
    acldvppSetPicDescFormat(encodeInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(encodeInputDesc_, input_w);
    acldvppSetPicDescHeight(encodeInputDesc_, input_h);
    acldvppSetPicDescWidthStride(encodeInputDesc_, input_w);
    acldvppSetPicDescHeightStride(encodeInputDesc_, input_h);
    acldvppSetPicDescSize(encodeInputDesc_, buffer_size);

    // 编码质量范围[0, 100]，其中level 0编码质量与level 100差不多，而在[1, 100]内数值越小输出图片质量越差。
    g_jpegeConfig_ = acldvppCreateJpegeConfig();
    acldvppSetJpegeConfigLevel(g_jpegeConfig_, 100);

    // 8. 申请输出内存，申请Device内存encodeOutBufferDev_,存放编码后的输出数据
    uint32_t outBufferSize= 0;
    aclError ret = acldvppJpegPredictEncSize(encodeInputDesc_, g_jpegeConfig_, &outBufferSize);
    ret = acldvppMalloc(&encodeOutBufferDev_, outBufferSize);

    // 9. 执行异步编码，再调用aclrtSynchronizeStream接口阻塞程序运行，直到指定Stream中的所有任务都完成
    aclRet = acldvppJpegEncodeAsync(g_dvppChannelDesc_, encodeInputDesc_, encodeOutBufferDev_, &outBufferSize, g_jpegeConfig_, g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"acldvppJpegEncodeAsync failed11111111, ret = "<<aclRet<<std::endl;
     
    }
    aclRet = aclrtSynchronizeStream(g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"aclrtSynchronizeStream failed11111111111, ret = "<<aclRet<<std::endl;
     
    }

     // 保存查看，device2host
    void* buffer1 = nullptr;
    aclRet  = aclrtMallocHost(&buffer1, outBufferSize);
    if (aclRet != ACL_SUCCESS) {
	std::cout << "aclrtMallocHost failed, result code is " << aclRet << std::endl;
    }
    
    aclRet = aclrtMemcpy(buffer1, outBufferSize, encodeOutBufferDev_, outBufferSize, ACL_MEMCPY_DEVICE_TO_HOST);
    FILE *fp;
    fp = fopen("./jpege_1280_1024.jpg", "w");
    fwrite((unsigned char *)buffer1, sizeof(unsigned char), outBufferSize, fp); 
    fclose(fp);

    dvpp_jpegeUninit();
    return 0;
}


int DVPP_VPC::dvpp_resize_jpege()
{   
    // void* encodeOutBufferDev_ = nullptr;
    // aclError aclRet = acldvppMalloc(&encodeOutBufferDev_, input)

    encodeInputDesc_ = acldvppCreatePicDesc();

    acldvppSetPicDescData(encodeInputDesc_, g_vpcOutBufferDev_);
    acldvppSetPicDescFormat(encodeInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(encodeInputDesc_, 640);
    acldvppSetPicDescHeight(encodeInputDesc_, 640);
    acldvppSetPicDescWidthStride(encodeInputDesc_, 640);
    acldvppSetPicDescHeightStride(encodeInputDesc_, 640);
    acldvppSetPicDescSize(encodeInputDesc_, 614400);

    // 编码质量范围[0, 100]，其中level 0编码质量与level 100差不多，而在[1, 100]内数值越小输出图片质量越差。
    g_jpegeConfig_ = acldvppCreateJpegeConfig();
    acldvppSetJpegeConfigLevel(g_jpegeConfig_, 100);

    // 8. 申请输出内存，申请Device内存encodeOutBufferDev_,存放编码后的输出数据
    uint32_t outBufferSize= 0;
    aclError ret = acldvppJpegPredictEncSize(encodeInputDesc_, g_jpegeConfig_, &outBufferSize);
    ret = acldvppMalloc(&encodeOutBufferDev_, outBufferSize);

    // 9. 执行异步编码，再调用aclrtSynchronizeStream接口阻塞程序运行，直到指定Stream中的所有任务都完成
    aclError aclRet = acldvppJpegEncodeAsync(g_dvppChannelDesc_, encodeInputDesc_, encodeOutBufferDev_, &outBufferSize, g_jpegeConfig_, g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"acldvppJpegEncodeAsync failed, ret = "<<aclRet<<std::endl;
     
    }
    aclRet = aclrtSynchronizeStream(g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"aclrtSynchronizeStream failed, ret = "<<aclRet<<std::endl;
     
    }

     // 保存查看，device2host
    void* buffer1 = nullptr;
    aclRet  = aclrtMallocHost(&buffer1, outBufferSize);
    if (aclRet != ACL_SUCCESS) {
	std::cout << "aclrtMallocHost failed, result code is " << aclRet << std::endl;
    }
    
    aclRet = aclrtMemcpy(buffer1, outBufferSize, encodeOutBufferDev_, outBufferSize, ACL_MEMCPY_DEVICE_TO_HOST);
    FILE *fp;
    fp = fopen("./1_640_640.jpg", "w");
    fwrite((unsigned char *)buffer1, sizeof(unsigned char), outBufferSize, fp);  // 1966080 614400
    fclose(fp);

    dvpp_jpegeUninit();
    return 0;
}


int DVPP_VPC::dvpp_crop(unsigned char * srcImage, uint32_t len, int input_w, int input_h, int top_x, int top_y, int output_w, int output_h)
{
    void* cropbuffer = nullptr;
    aclError aclRet = acldvppMalloc(&cropbuffer, len);
    aclRet = aclrtMemcpy(cropbuffer, len, srcImage, len, ACL_MEMCPY_HOST_TO_DEVICE);

    g_cropConfig_ = acldvppCreateRoiConfig(top_x, top_x + output_w, top_y, top_y + output_h);   // 抠图x起点、x起点偏移、y起点、y起点偏移

    g_cropInputDesc_ = acldvppCreatePicDesc();

    uint32_t cropInputBufferSize_ = YUV420SP_SIZE(input_w, input_h);

    acldvppSetPicDescData(g_cropInputDesc_, cropbuffer);
    acldvppSetPicDescFormat(g_cropInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(g_cropInputDesc_, input_w);
    acldvppSetPicDescHeight(g_cropInputDesc_, input_h);
    acldvppSetPicDescWidthStride(g_cropInputDesc_, input_w);
    acldvppSetPicDescHeightStride(g_cropInputDesc_, input_h);
    acldvppSetPicDescSize(g_cropInputDesc_, cropInputBufferSize_);

    
    //4. 创建crop输出图片的描述信息，并设置各属性值
    uint32_t cropOutputBufferSize_ = YUV420SP_SIZE(output_w, output_h);
    aclRet = acldvppMalloc(&g_cropOutBufferDev_, cropOutputBufferSize_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"acldvppMalloc g_cropOutBufferDev_ failed"<<std::endl;
        return 1;
    }


    g_cropOutputDesc_ = acldvppCreatePicDesc();

    acldvppSetPicDescData(g_cropOutputDesc_, g_cropOutBufferDev_);
    acldvppSetPicDescFormat(g_cropOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(g_cropOutputDesc_, output_w);
    acldvppSetPicDescHeight(g_cropOutputDesc_, output_h);
    acldvppSetPicDescWidthStride(g_cropOutputDesc_, output_w);
    acldvppSetPicDescHeightStride(g_cropOutputDesc_, output_h);
    acldvppSetPicDescSize(g_cropOutputDesc_, cropOutputBufferSize_);

    aclRet = acldvppVpcCropAsync(g_dvppChannelDesc_, g_cropInputDesc_, g_cropOutputDesc_, g_cropConfig_, g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"acldvppVpcCropAsync failed, ret = "<<aclRet<<std::endl;
     
    }
    aclRet = aclrtSynchronizeStream(g_stream_);
    if (aclRet != ACL_SUCCESS) {
        std::cout<<"crop aclrtSynchronizeStream failed, ret = "<<aclRet<<std::endl;
     
    }

     // 保存查看，device2host
    void* buffer1 = nullptr;
    aclRet  = aclrtMallocHost(&buffer1, 614400);
    if (aclRet != ACL_SUCCESS) {
	std::cout << "aclrtMallocHost failed, result code is " << aclRet << std::endl;
    }
    
    aclRet = aclrtMemcpy(buffer1, 614400, g_cropOutBufferDev_, 614400, ACL_MEMCPY_DEVICE_TO_HOST);
    FILE *fp;
    fp = fopen("./crop_640_640.yuv", "w");
    fwrite((unsigned char *)buffer1, sizeof(unsigned char), 614400, fp);  // 1966080 614400
    fclose(fp);
}



void DVPP_VPC::dvpp_resizeUninit()
{
    if (g_resizeConfig_ != nullptr) {
        (void)acldvppDestroyResizeConfig(g_resizeConfig_);
        g_resizeConfig_ = nullptr;
    }

    // 缩放结束后，释放资源，包括缩放输入/输出图片的描述信息、缩放输入/输出内存
    if (g_vpcInputDesc_ != nullptr) {
        (void)acldvppDestroyPicDesc(g_vpcInputDesc_);
        g_vpcInputDesc_ = nullptr;
    }

    if (g_vpcOutputDesc_ != nullptr) {
        (void)acldvppDestroyPicDesc(g_vpcOutputDesc_);
        g_vpcOutputDesc_ = nullptr;
    }
}

void DVPP_VPC::dvpp_jpegeUninit()
{
    if (g_jpegeConfig_ != nullptr) {
        (void)acldvppDestroyJpegeConfig(g_jpegeConfig_);
        g_jpegeConfig_ = nullptr;
    }

    if (encodeInputDesc_ != nullptr) {
        (void)acldvppDestroyPicDesc(encodeInputDesc_);
        encodeInputDesc_ = nullptr;
    }
}

void DVPP_VPC::dvpp_cropUninit()
{
    if (g_cropConfig_ != nullptr) {
        (void)acldvppDestroyRoiConfig(g_cropConfig_);
        g_jpegeConfig_ = nullptr;
    }

    if (encodeInputDesc_ != nullptr) {
        (void)acldvppDestroyPicDesc(g_cropInputDesc_);
        encodeInputDesc_ = nullptr;
    }

    if (encodeInputDesc_ != nullptr) {
        (void)acldvppDestroyPicDesc(g_cropOutputDesc_);
        encodeInputDesc_ = nullptr;
    }
}